package com.zhirun.SpringJdbcSupport;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.jdbc.core.RowMapper;

import com.zhirun.SpringJdbcSupport.anotations.Column;
import com.zhirun.SpringJdbcSupport.anotations.CustomizeClass;

/**
 * 将查询结果转为对象 bean中的各getter和setter方法中，属性首字母大写，数据库中的字段与bean中属性名相同
 * 
 * @author 刘润枝
 *
 **/

public class ORMapper<T> implements RowMapper<T> {
	private Class<?> cls;// 需要映射的对象名
	private static Map<String, Integer> type = new HashMap<String, Integer>();

	public ORMapper(Class<?> cls) {
		this.cls = cls;
		type.put("java.lang.String", 1);
		type.put("int", 2);
		type.put("java.math.BigDecimal", 3);
		type.put("java.util.List", 4);
		type.put("java.util.Date", 5);
		type.put("java.sql.Date", 6);
	}

	@SuppressWarnings("unchecked")
	@Override
	public T mapRow(ResultSet rs, int rowNum) throws SQLException {
		try {
			// 实例化映射对象
			Object obj = cls.newInstance();
			Field[] fields = cls.getDeclaredFields();
			// 遍历属性，并调用set方法，为对象属性赋值
			for (Field field : fields) {
				try {
					String name = field.getName();
					String methodStr = "set" + name.toUpperCase().substring(0, 1) + name.substring(1);
					Method method;
					method = cls.getMethod(methodStr, new Class[] { field.getType() });
					if (field.getAnnotation(CustomizeClass.class) != null) {
						method.invoke(obj, this.buildObject(rs, field.getType()));
					} else if (field.getAnnotation(Column.class) != null) {
						Column col = field.getAnnotation(Column.class);
						this.setNormalType(rs, field, method, obj, col.name()[0]);
					} else {
						this.setNormalType(rs, field, method, obj, name);
					}
				} catch (NoSuchMethodException e) {
					e.printStackTrace();
					continue;
				} catch (SQLException e) {
					continue;
				}
			}
			return (T) obj;
		} catch (ClassNotFoundException e) {

			e.printStackTrace();
		} catch (IllegalAccessException e) {

			e.printStackTrace();
		} catch (IllegalArgumentException e) {

			e.printStackTrace();
		} catch (InvocationTargetException e) {

			e.printStackTrace();
		} catch (InstantiationException e) {

			e.printStackTrace();
		}
		return null;
	}

	public void setNormalType(ResultSet rs, Field field, Method method, Object obj, String filedName)
			throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, SQLException {
		int paramType = 1;
		try {
			paramType = type.get(field.getType().getName());
		}catch(Exception e) {
		}
		switch (paramType) {
		case 1:
			method.invoke(obj, rs.getString(filedName));
			break;
		case 2:
			method.invoke(obj, rs.getInt(filedName));
			break;
		case 3:
			method.invoke(obj, rs.getBigDecimal(filedName));
			break;
		case 4:
			method.invoke(obj, buildList(rs, field));
			break;
		case 5:
			method.invoke(obj, rs.getDate(filedName));
			break;
		case 6:
			method.invoke(obj, rs.getDate(filedName));
			break;
		default:
			break;
		}
	}

	public Object buildObject(ResultSet rs, Class<?> cls) throws ClassNotFoundException, InstantiationException,
			IllegalAccessException, IllegalArgumentException, InvocationTargetException, SQLException {
		Class<?> clazz = Class.forName(cls.getName());
		Object obj = clazz.newInstance();
		Field[] fields = clazz.getDeclaredFields();
		// 遍历属性，并调用set方法，为对象属性赋值
		for (Field field : fields) {
			String name = field.getName();
			try {
				String methodStr = "set" + name.toUpperCase().substring(0, 1) + name.substring(1);
				Method method;
				method = cls.getMethod(methodStr, new Class[] { field.getType() });
				if (field.getAnnotation(CustomizeClass.class) != null) {
					method.invoke(obj, this.buildObject(rs, field.getType()));
				} else {
					this.setNormalType(rs, field, method, obj, name);
				}
			} catch (NoSuchMethodException e) {
				e.printStackTrace();
				continue;
			} catch (SQLException e) {
				continue;
			}
		}
		return obj;
	}

	@SuppressWarnings({ "unchecked", "rawtypes" })
	public Object buildList(ResultSet rs, Field field) {
		Type genericType = field.getGenericType();
		if (genericType != null) {
			if (genericType instanceof ParameterizedType) {
				ParameterizedType pt = (ParameterizedType) genericType;
				// 得到泛型里的class类型对象
				Class<?> genericClazz = (Class<?>) pt.getActualTypeArguments()[0];
				Object obj = null;
				try {
					obj = this.buildObject(rs, genericClazz);
				} catch (ClassNotFoundException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (InstantiationException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (IllegalAccessException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (IllegalArgumentException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (InvocationTargetException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (SQLException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				List list = new ArrayList();
				list.add(obj);
				return list;
			}
		}
		return null;
	}

}
